#include "stdafx.h"
#include "EditorRenderStage.h"

#include "GlobalAppData.h"
#include "RenderingData.h"
#include "RenderingSettings.h"
#include "LoadShader.h"
#include "LoadTexture.h"
#include "InputLayouts.h"
#include "Mesh.h"
#include "Renderer.h"
#include "2DUtils.h"
#include "DebugDraw.h"

using namespace mgfx;

TextureID pointLightTex;
TextureID spotLightTex;
TextureID partSystemTex;

ShaderID wireframeShader;

static void drawIcons( const RenderingData & data )
{
	uint scrWid = mcore::GlobalAppData::Instance.ScreenWidth;
	uint scrHei = mcore::GlobalAppData::Instance.ScreenHeight;

	XMMATRIX view, proj, viewProj, worldView;
	view = XMLoadFloat4x4(&data.ViewMatrix);
	proj = XMLoadFloat4x4(&data.ProjMatrix);
	viewProj = XMMatrixMultiply(view, proj);

	for(uint i = 0; i < data.PointLights.NumElements; i++)
	{
		const PointLight & light = data.PointLights[i];

		XMVECTOR lightPos = XMVector3Transform(XMLoadFloat3(&light.Position), viewProj);
		float xPos = XMVectorGetX(lightPos) / XMVectorGetW(lightPos);
		float yPos = XMVectorGetY(lightPos) / XMVectorGetW(lightPos);
		Utils2D::drawRectTextured(
			(uint)((xPos * 0.5f + 0.5f) * scrWid) - 16,
			(uint)((-yPos * 0.5f + 0.5f) * scrHei) - 16,
			32, 32, pointLightTex);
	}

	for(uint i = 0; i < data.SpotLights.NumElements; i++)
	{
		const SpotLight & light = data.SpotLights[i];

		XMVECTOR lightPos = XMVector3Transform(XMLoadFloat3(&light.Position), viewProj);
		float xPos = XMVectorGetX(lightPos) / XMVectorGetW(lightPos);
		float yPos = XMVectorGetY(lightPos) / XMVectorGetW(lightPos);
		Utils2D::drawRectTextured(
			(uint)((xPos * 0.5f + 0.5f) * scrWid) - 16,
			(uint)((-yPos * 0.5f + 0.5f) * scrHei) - 16,
			32, 32, spotLightTex);
	}

	for(uint i = 0; i < data.PartSystems.NumElements; i++)
	{
		const ParticleSystem & ps = data.PartSystems[i];

		XMVECTOR pos = XMVector3Transform(XMLoadFloat3(&ps.Position), viewProj);
		float xPos = XMVectorGetX(pos) / XMVectorGetW(pos);
		float yPos = XMVectorGetY(pos) / XMVectorGetW(pos);
		Utils2D::drawRectTextured(
			(uint)((xPos * 0.5f + 0.5f) * scrWid) - 16,
			(uint)((-yPos * 0.5f + 0.5f) * scrHei) - 16,
			32, 32, partSystemTex);
	}
}

static void drawSelectedMeshes(const RenderingData & data, const EditorRenderData & debugData)
{
	XMMATRIX view, proj, viewProj, worldView;
	view = XMLoadFloat4x4(&data.ViewMatrix);
	proj = XMLoadFloat4x4(&data.ProjMatrix);
	viewProj = XMMatrixMultiply(view, proj);

	Renderer * rdr = Renderer::Instance;

	rdr->setVertexFormat(VertexPosition::VertexFormat);
	rdr->setPrimitiveType(TRIANGLE_LIST);

	for (size_t meshIdx = 0; meshIdx < debugData.SelectedMeshes.size(); meshIdx++)
	{
		const MeshInstance & meshInst = *(debugData.SelectedMeshes[meshIdx]);

		Mesh & mesh = *meshInst.Mesh_;
		Material & material = *meshInst.Material_;

		XMMATRIX wvp = XMMatrixMultiply(XMLoadFloat4x4(&meshInst.WorldTransform), viewProj);

		rdr->setShader(wireframeShader);
		rdr->setShaderMatrix("gWVP", (float*)&wvp);

		uint partsSize = mesh.GetParts().size();
		for (uint partIdx = 0; partIdx < partsSize; partIdx++)
		{
			const Mesh::Part & part = mesh.GetParts()[partIdx];

			mmath::BoundingSphere meshBSphere = mmath::BoundingSphere::transform(part.BSphere,
				XMLoadFloat3(&meshInst.Position), XMLoadFloat4(&meshInst.Orientation), XMLoadFloat3(&meshInst.Scale));
			if(!mmath::frustumSphereintersects(data.ViewFrustum.Planes, meshBSphere))
				continue;

			uint stride = sizeof(VertexPosition);
			uint offset = 0;

			rdr->setVertexBuffer(part.VBPositionsOnly);
			rdr->setIndexBuffer(part.IB);

			rdr->drawIndexed();
		}
	}
}

static void drawSelectedLights(const RenderingData & data, const EditorRenderData & debugData)
{
	XMMATRIX viewProj = XMLoadFloat4x4(&data.ViewProjMatrix);

	for(uint i = 0; i < debugData.SelectedPointLighs.size(); i++)
		debug::renderPointLightBoundingSphere(*debugData.SelectedPointLighs[i], viewProj);

	for(uint i = 0; i < debugData.SelectedSpotLights.size(); i++)
		debug::renderSpotLightBoundingCone(*debugData.SelectedSpotLights[i], viewProj);
}

static void drawSelectedParticleSystems(const RenderingData & data, const EditorRenderData & debugData)
{
	XMMATRIX viewProj = XMLoadFloat4x4(&data.ViewProjMatrix);

	for(uint i = 0; i < debugData.SelectedPartSystems.size(); i++)
		debug::renderBoundingBox(debugData.SelectedPartSystems[i]->MaxBoundingBox, viewProj);
}

void mgfx::initEditorRenderStage()
{
	wireframeShader = loadShaderFromFile("Wireframe.fx");
	pointLightTex = loadTextureFromFile("pointlight.jpg");
	spotLightTex = loadTextureFromFile("spotlight.jpg");
	partSystemTex = loadTextureFromFile("particle-system-icon.jpg");
}

void mgfx::renderEditorData(const RenderingData & data, const EditorRenderData & debugData, const RenderingSettings & settings)
{
	if(settings.DisplayIcons)
		drawIcons(data);

	drawSelectedMeshes(data, debugData);
	drawSelectedLights(data, debugData);
	drawSelectedParticleSystems(data, debugData);

}
